package com.kexio.file.config;

import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
import org.springframework.util.StringUtils;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.kexio.file.entity.FileStorageConfig;
import com.kexio.file.mapper.FileStorageConfigMapper;
import com.kexio.file.storage.StorageManager;

/**
 * 文件存储配置类
 * 
 * 初始化文件存储相关的配置和组件
 * 
 * @author Kexio Team
 * @since 1.0.0
 */
@Configuration
@EnableConfigurationProperties(FileStorageProperties.class)
public class FileStorageConfiguration {
    
    private static final Logger log = LoggerFactory.getLogger(FileStorageConfiguration.class);
    
    @Autowired
    private StorageManager storageManager;
    
    @Autowired
    private FileStorageProperties storageProperties;
    
    @Autowired
    private FileStorageConfigMapper fileStorageConfigMapper;
    
    @Autowired
    private ObjectMapper objectMapper;
    
    /**
     * 初始化存储管理器
     * 使用 ApplicationReadyEvent 确保在所有 Bean 初始化完成后再执行
     * 避免 MyBatis Mapper 尚未完全初始化时就被调用
     */
    @EventListener(ApplicationReadyEvent.class)
    public void initializeStorageManager() {
        log.info("初始化文件存储配置...");
        
        // 从新的多配置系统加载默认配置并覆盖内存配置
        try {
            FileStorageConfig defaultConfig = getDefaultConfigFromMapper();
            if (defaultConfig != null && defaultConfig.getIsEnabled()) {
                applyStorageConfig(defaultConfig);
                log.info("文件存储配置已从数据库加载并生效: {}", defaultConfig.getConfigName());
            } else {
                log.info("未找到默认存储配置，使用内存配置");
                ensureDefaultConfig();
            }
        } catch (Exception e) {
            log.warn("从数据库加载文件存储配置失败，使用内存默认配置", e);
            ensureDefaultConfig();
        }
        
        // 初始化存储提供者
        storageManager.initializeProviders();
        
        // 创建默认存储桶
        try {
            String defaultBucket = storageProperties.getDefaultBucket();
            storageManager.getDefaultProvider().createBucketIfNotExists(defaultBucket);
            log.info("默认存储桶初始化完成: {}", defaultBucket);
        } catch (Exception e) {
            log.warn("默认存储桶初始化失败", e);
        }
        
        log.info("文件存储配置初始化完成");
        log.info("默认存储提供者: {}", storageProperties.getDefaultProvider());
        log.info("默认存储桶: {}", storageProperties.getDefaultBucket());
        log.info("最大文件大小: {} MB", storageProperties.getUpload().getMaxFileSize() / (1024 * 1024));
    }
    
    /**
     * 应用存储配置到内存属性
     */
    private void applyStorageConfig(FileStorageConfig config) {
        try {
            // 设置存储类型
            storageProperties.setDefaultProvider(config.getConfigType());
            
            // 解析配置参数
            if (StringUtils.hasText(config.getConfigParams())) {
                JsonNode params = objectMapper.readTree(config.getConfigParams());
                
                // 设置默认存储桶
                if (params.has("bucketName")) {
                    storageProperties.setDefaultBucket(params.get("bucketName").asText());
                }
                
                // 本地存储配置
                if ("local".equals(config.getConfigType())) {
                    if (params.has("rootPath")) {
                        storageProperties.getLocal().setRootPath(params.get("rootPath").asText());
                    }
                    if (params.has("createDateSubDir")) {
                        storageProperties.getLocal().setCreateDateSubDir(params.get("createDateSubDir").asBoolean());
                    }
                }
                
                // MinIO 配置
                if ("minio".equalsIgnoreCase(config.getConfigType())) {
                    var minio = storageProperties.getMinio();
                    if (params.has("endpoint")) minio.setEndpoint(params.get("endpoint").asText());
                    if (params.has("accessKey")) minio.setAccessKey(params.get("accessKey").asText());
                    if (params.has("secretKey")) minio.setSecretKey(params.get("secretKey").asText());
                    if (params.has("secure")) minio.setSecure(params.get("secure").asBoolean(false));
                    if (params.has("region")) minio.setRegion(params.get("region").asText());
                    if (params.has("connectTimeout")) minio.setConnectTimeout(params.get("connectTimeout").asInt(30));
                    if (params.has("readTimeout")) minio.setReadTimeout(params.get("readTimeout").asInt(60));
                    minio.setEnabled(true);
                    // 基础必填校验
                    requireNonBlank(minio.getEndpoint(), "MinIO endpoint 未配置");
                    requireNonBlank(minio.getAccessKey(), "MinIO accessKey 未配置");
                    requireNonBlank(minio.getSecretKey(), "MinIO secretKey 未配置");
                }

                // 阿里云 OSS 配置
                if ("oss".equalsIgnoreCase(config.getConfigType())) {
                    var oss = storageProperties.getOss();
                    if (params.has("endpoint")) oss.setEndpoint(params.get("endpoint").asText());
                    if (params.has("accessKeyId")) oss.setAccessKeyId(params.get("accessKeyId").asText());
                    if (params.has("accessKeySecret")) oss.setAccessKeySecret(params.get("accessKeySecret").asText());
                    if (params.has("securityToken")) oss.setSecurityToken(params.get("securityToken").asText());
                    oss.setEnabled(true);
                    // 必填校验
                    requireNonBlank(oss.getEndpoint(), "OSS endpoint 未配置");
                    requireNonBlank(oss.getAccessKeyId(), "OSS accessKeyId 未配置");
                    requireNonBlank(oss.getAccessKeySecret(), "OSS accessKeySecret 未配置");
                }

                // 腾讯云 COS 配置
                if ("cos".equalsIgnoreCase(config.getConfigType())) {
                    var cos = storageProperties.getCos();
                    if (params.has("appId")) cos.setAppId(params.get("appId").asText());
                    if (params.has("secretId")) cos.setSecretId(params.get("secretId").asText());
                    if (params.has("secretKey")) cos.setSecretKey(params.get("secretKey").asText());
                    if (params.has("region")) cos.setRegion(params.get("region").asText());
                    cos.setEnabled(true);
                    // 必填校验
                    requireNonBlank(cos.getAppId(), "COS appId 未配置");
                    requireNonBlank(cos.getSecretId(), "COS secretId 未配置");
                    requireNonBlank(cos.getSecretKey(), "COS secretKey 未配置");
                    requireNonBlank(cos.getRegion(), "COS region 未配置");
                }

                // 七牛云 Kodo 配置
                if ("qiniu".equalsIgnoreCase(config.getConfigType())) {
                    var qn = storageProperties.getQiniu();
                    if (params.has("accessKey")) qn.setAccessKey(params.get("accessKey").asText());
                    if (params.has("secretKey")) qn.setSecretKey(params.get("secretKey").asText());
                    if (params.has("region")) qn.setRegion(params.get("region").asText());
                    if (params.has("domain")) qn.setDomain(params.get("domain").asText());
                    if (params.has("useHttps")) qn.setUseHttps(params.get("useHttps").asBoolean(true));
                    qn.setEnabled(true);
                    // 必填校验
                    requireNonBlank(qn.getAccessKey(), "七牛 accessKey 未配置");
                    requireNonBlank(qn.getSecretKey(), "七牛 secretKey 未配置");
                    requireNonBlank(qn.getRegion(), "七牛 region 未配置");
                }

                // 分享配置
                if (storageProperties.getShare() == null) {
                    storageProperties.setShare(new FileStorageProperties.ShareConfig());
                }
                if (params.has("shareBaseUrl")) {
                    storageProperties.getShare().setBaseUrl(params.get("shareBaseUrl").asText());
                }
                if (params.has("sharePathPrefix")) {
                    storageProperties.getShare().setPathPrefix(params.get("sharePathPrefix").asText());
                }
            }
            
        } catch (Exception e) {
            log.error("应用存储配置失败: {}", config.getConfigName(), e);
            ensureDefaultConfig();
        }
    }

    /**
     * 简单必填检查
     */
    private void requireNonBlank(String value, String message) {
        if (!StringUtils.hasText(value)) {
            throw new IllegalArgumentException(message);
        }
    }
    
    /**
     * 确保有默认配置
     */
    private void ensureDefaultConfig() {
        if (!StringUtils.hasText(storageProperties.getDefaultProvider())) {
            storageProperties.setDefaultProvider("local");
        }
        if (!StringUtils.hasText(storageProperties.getDefaultBucket())) {
            storageProperties.setDefaultBucket("kexio-files");
        }
        if (storageProperties.getLocal().getRootPath() == null) {
            storageProperties.getLocal().setRootPath("./storage");
        }
        // createDateSubDir 是基本类型boolean，不会为null，使用默认值即可
        if (storageProperties.getShare() == null) {
            storageProperties.setShare(new FileStorageProperties.ShareConfig());
        }
        if (!StringUtils.hasText(storageProperties.getShare().getPathPrefix())) {
            storageProperties.getShare().setPathPrefix("/share/");
        }
        
        log.info("已设置默认存储配置");
    }
    
    /**
     * 重新加载存储配置（用于配置热更新）
     * 当用户更改默认配置时调用此方法，无需重启系统即可生效
     */
    public void reloadStorageConfiguration() {
        log.info("开始重新加载文件存储配置...");
        
        try {
            FileStorageConfig defaultConfig = getDefaultConfigFromMapper();
            if (defaultConfig != null && defaultConfig.getIsEnabled()) {
                applyStorageConfig(defaultConfig);
                
                // 重新初始化存储提供者
                storageManager.initializeProviders();
                
                // 创建默认存储桶
                String defaultBucket = storageProperties.getDefaultBucket();
                storageManager.getDefaultProvider().createBucketIfNotExists(defaultBucket);
                
                log.info("✅ 存储配置热更新成功: {} -> {}", 
                         defaultConfig.getConfigName(), 
                         defaultConfig.getConfigType());
                log.info("新的存储提供者: {}", storageProperties.getDefaultProvider());
                log.info("新的存储桶: {}", storageProperties.getDefaultBucket());
                
            } else {
                log.warn("未找到有效的默认存储配置");
            }
        } catch (Exception e) {
            log.error("存储配置热更新失败", e);
            throw new RuntimeException("配置更新失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 获取当前生效的存储配置信息（用于监控和调试）
     */
    public Map<String, Object> getCurrentStorageInfo() {
        Map<String, Object> info = new HashMap<>();
        info.put("defaultProvider", storageProperties.getDefaultProvider());
        info.put("defaultBucket", storageProperties.getDefaultBucket());
        info.put("localRootPath", storageProperties.getLocal().getRootPath());
        info.put("localCreateDateSubDir", storageProperties.getLocal().isCreateDateSubDir());
        if (storageProperties.getShare() != null) {
            info.put("shareBaseUrl", storageProperties.getShare().getBaseUrl());
            info.put("sharePathPrefix", storageProperties.getShare().getPathPrefix());
        }
        info.put("lastReloadTime", System.currentTimeMillis());
        return info;
    }
    
    /**
     * 直接从Mapper获取默认配置（避免循环依赖）
     * 租户ID由MyBatis-Plus租户拦截器自动处理
     */
    private FileStorageConfig getDefaultConfigFromMapper() {
        // 不需要手动传递tenantId，由MyBatis-Plus租户拦截器自动添加WHERE条件
        return fileStorageConfigMapper.selectDefaultByTenantId();
    }
}
